<?php
/**
 * Klasse zur Validierung von Variablen und Variablenarrays
 *
 * @author		Joachim Ruf
 * @copyright	Copyright (c) 2003-2010 Loresoft Software (http://www.loresoft.de)
 * @license		http://yapary.loresoft.de/lizenzbedingungen     New BSD License
 *
 * */

Class Yapary_Parameter_Parameter
{
    /** @desc Speichert die zuletzt benutze Validierungsklasse */
    private $classValidation;
    /** @var Speichert alle vorgenommenen Validierungsinformationen im Format array[] = $errno */
    private $arrStatusHistory = array();
    private $status           = NULL;

	function __construct ()
	{

	}


	/**
	* Validiert die "Values" eines Arrays auf Gueltigkeit
	* @param mixed $arrayToValidate	: Die zu pruefende Variable
	* @param mixed $defaultValue 	: Standardwert, falls Variable nicht existent oder ueberpruefung ungueltig
	* @param Class $classValidation : eine der Parameter... Validierungsklassen
	* @return mixed : Wert oder defaultwert
	*/
	public function getArray ( $arrayToValidate, $defaultValue = NULL, $oValidator )
	{
	    $arrResult = array();

	    if (count($arrayToValidate)) {
	        while (list($key,$val) = each($arrayToValidate)) {
	            $arrResult[$key] = $this->getParam($val, $defaultValue, $oValidator);
	        }
	    }

	    return $arrResult;
	}


	/**
	* Prueft eine Variable auf Gueltigkeit
	* @param mixed $paramToValidate	: Die zu pruefende Variable
	* @param mixed $defaultValue 	: Standardwert, falls Variable nicht existent oder ueberpruefung ungueltig
	* @param Class $classValidation : eine der Parameter... Validierungsklassen
	* @return mixed : Wert oder defaultwert
	*/
	public function getParam ( $paramToValidate, $defaultValue = NULL, $oValidator )
	{
		$this->status = NULL;
		$this->classValidation = NULL;
	    // Validierungsklassen ueberpruefen, Fehlererkennung uebertragen und Wert ausgeben

		if (!is_object($oValidator)) {
			throw new Exception('Parameter 3 muss eine Instanz einer Validierungsklasse sein');
		}

		$o = new ReflectionClass($oValidator);
		if (!$o->isSubclassOf('Yapary_Exception_Error')) {
			throw new Exception('Validierungsklasse ist nicht abgeleitet von ParameterStatus');
		}

		if (!$o->implementsInterface('IParameterCheck')) {
			throw new Exception('Validierungsklasse ist keine abgeleitete Klasse von IParameterCheck');
		}


		$this->classValidation = $oValidator;
		if ($oValidator->isValid($paramToValidate)) {
		    $this->status = $this->arrStatusHistory[] = $oValidator->getLastError();
        	return $oValidator->typedef($paramToValidate);
		}

	    $this->status = $this->arrStatusHistory[] = $oValidator->getLastError();
        return $defaultValue;
	}


	/**
	 * Gibt den zuletzt erzeugten Status einerValidierung zurueck
	 * @return string|NULL
	 * */
	public function getStatus ()
	{
	    return $this->status;
	}

	/**
	 * Gibt die gespeicherten Validierungsinformationen in der Aufrufreihenfolge aus
	 * @return array() : array[] = $errno
	 * */
	public function getStatusHistory()
	{
	    return $this->arrStatusHistory;
	}

}



// ========== Interface der Validierungsklassen ==========



interface IParameterCheck
{
	public function typedef ( $val );
	public function isValid ( $val );
}



// ========== Validierungsklassen ==========



/**
 * $val muss einer Zahlenfolge entsprechen
 * */
Class Yapary_Parameter_ParameterCheckNumeric Extends Yapary_Exception_Error Implements IParameterCheck
{
	private $min, $max;
	function __construct ( $_min = NULL, $_max = NULL )
	{
		$this->min = $_min;
		$this->max = $_max;
	}
	public function typedef ( $val )
	{
		if (strlen($val) <= 10) {
			return (int) $val;
		}
		return (string) $val;
	}
	public function isValid ( $val )
	{
		if (!isset($val)) {
			$this->addError(Yapary_Exception_Error::E_UNDEFINED);
			return false;
		}
		if ($this->min != NULL && $val < $this->min) {
			$this->addError(Yapary_Exception_Error::E_OUT_OF_SCOPE);
			return false;
		}
		if ($this->max != NULL && $val > $this->max) {
			$this->addError(Yapary_Exception_Error::E_OUT_OF_SCOPE);
			return false;
		}
		if (!is_numeric($val)) {
			$this->addError(Yapary_Exception_Error::E_WRONG_FORMAT);
			return false;
		}

		return true;
	}
}


/**
 * $val muss einem Zahlenfolge mit vorgegebener Unteren- und/oder Oberen Zeichenlaenge entsprechen
 * */
Class Yapary_Parameter_ParameterCheckNumericLength Extends Yapary_Exception_Error Implements IParameterCheck
{
	private $min, $max;
	function __construct ( $_minLength, $_maxLength )
	{
		$this->min = $_minLength;
		$this->max = $_maxLength;
	}
	public function typedef ( $val )
	{
		if (strlen($val) <= 10)
			return (int) $val;
		return (string) $val;
	}
	public function isValid ( $val )
	{
		if (!isset($val)) {
			$this->addError(Yapary_Exception_Error::E_UNDEFINED);
			return false;
		}
		if ($this->min != NULL && strlen($val) < $this->min) {
			$this->addError(Yapary_Exception_Error::E_OUT_OF_SIZE);
			return false;
		}
		if ($this->max != NULL && strlen($val) > $this->max) {
			$this->addError(Yapary_Exception_Error::E_OUT_OF_SIZE);
			return false;
		}
		if (!is_numeric($val) ){
			$this->addError(Yapary_Exception_Error::E_WRONG_FORMAT);
			return false;
		}

        return true;
	}
}


/**
 * $val muss einem Int mit vorgegebener Unter- und/oder Obergrenze entsprechen
 * */
Class Yapary_Parameter_ParameterCheckInt Extends Yapary_Exception_Error Implements IParameterCheck
{
	private $min, $max;
	function __construct ( $_min = NULL, $_max = NULL )
	{
		$this->min = $_min;
		$this->max = $_max;
	}
	public function typedef ( $val ) { return (int) $val;} // Hier Unterscheidung <=10 (int) und >10 (string)
	public function isValid ( $val )
	{
		if (!isset($val)) {
			$this->addError(Yapary_Exception_Error::E_UNDEFINED);
			return false;
		}
		if (!is_int($val)) {
		    return false;
		}
		if ($this->min != NULL && $val < $this->min) {
			$this->addError(Yapary_Exception_Error::E_OUT_OF_SCOPE);
			return false;
		}
		if ($this->max != NULL && $val > $this->max) {
			$this->addError(Yapary_Exception_Error::E_OUT_OF_SCOPE);
			return false;
		}

        return true;
	}
}


/**
 * $val muss einem Double mit vorgegebener Unter- und/oder Obergrenze entsprechen
 * */
Class Yapary_Parameter_ParameterCheckDouble Extends Yapary_Exception_Error Implements IParameterCheck
{
	private $min, $max;
	function __construct ( $_min = NULL, $_max = NULL )
	{
		$this->min = $_min;
		$this->max = $_max;
	}
	public function typedef ( $val ) { return (double) $val;}
	public function isValid ( $val )
	{
		if (!isset($val)) {
			$this->addError(Yapary_Exception_Error::E_UNDEFINED);
			return false;
		}
		if ($this->min != NULL && $val < $this->min) {
			$this->addError(Yapary_Exception_Error::E_OUT_OF_SCOPE);
			return false;
		}
		if ($this->max != NULL && $val > $this->max) {
			$this->addError(Yapary_Exception_Error::E_OUT_OF_SCOPE);
			return false;
		}
		if (!is_double($val)) {
			$this->addError(Yapary_Exception_Error::E_WRONG_FORMAT);
			return false;
		}

		return true;
	}
}


/**
 * $val muss einem String mit vorgegebener Unteren- und/oder Oberen Zeichenlaenge entsprechen
 * */
Class Yapary_Parameter_ParameterCheckString Extends Yapary_Exception_Error Implements IParameterCheck
{
	private $min, $max;
	function __construct ( $_minLength = NULL, $_maxLength = NULL )
	{
		$this->min = $_minLength;
		$this->max = $_maxLength;
	}
	public function typedef ( $val ) { return (string) $val;}
	public function isValid ( $val )
	{
		if (!isset($val)) {
			$this->addError(Yapary_Exception_Error::E_UNDEFINED);
			return false;
		}
		if ($this->min != NULL && strlen($val) < $this->min) {
			$this->addError(Yapary_Exception_Error::E_OUT_OF_SIZE);
			return false;
		}
		if ($this->max != NULL && strlen($val) > $this->max) {
			$this->addError(Yapary_Exception_Error::E_OUT_OF_SIZE);
			return false;
		}
		if (!is_string($val)) {
			$this->addError(Yapary_Exception_Error::E_WRONG_FORMAT);
			return false;
		}

		return true;
	}
}


/**
 * $val muss einem String aus folgenden Zeichen bestehen {a-z 0-9 - _ .}
 * darf ansonsten keinerlei Sonderzeichen enthalten
 * mit vorgegebener Unteren- und/oder Oberen Zeichenlaenge
 * */
Class Yapary_Parameter_ParameterCheckStringStrict Extends Yapary_Exception_Error Implements IParameterCheck
{
	private $min, $max;
	function __construct ( $_minLength = NULL, $_maxLength = NULL )
	{
		$this->min = $_minLength;
		$this->max = $_maxLength;
	}
	public function typedef ( $val ) { return (string) $val;}
	public function isValid ( $val )
	{
		if (!isset($val)) {
			$this->addError(Yapary_Exception_Error::E_UNDEFINED);
			return false;
		}
		if ($this->min != NULL && strlen($val) < $this->min) {
			$this->addError(Yapary_Exception_Error::E_OUT_OF_SIZE);
			return false;
		}
		if ($this->max != NULL && strlen($val) > $this->max) {
			$this->addError(Yapary_Exception_Error::E_OUT_OF_SIZE);
			return false;
		}
		if (!preg_match("/^([a-z0-9-_\.]*)$/i", $val)) {
			$this->addError(Yapary_Exception_Error::E_WRONG_FORMAT);
			return false;
		}

		return true;
	}
}


/**
 * $val muss einem String darf nur folgende Zeichen enthalten {a-z 0-9 - _ \ / . , : ; & = ? % # + * ( ) [ ] { }}
 * darf ansonsten keinerlei Sonderzeichen enthalten
 * mit vorgegebener Unteren- und/oder Oberen Zeichenlaenge
 * */
Class Yapary_Parameter_ParameterCheckStringPrecise Extends Yapary_Exception_Error Implements IParameterCheck
{
	private $min, $max;
	function __construct ( $_minLength = NULL, $_maxLength = NULL )
	{
		$this->min = $_minLength;
		$this->max = $_maxLength;
	}
	public function typedef ( $val ) { return (string) $val;}
	public function isValid ( $val )
	{
		if (!isset($val)) {
			$this->addError(Yapary_Exception_Error::E_UNDEFINED);
			return false;
		}
		if ($this->min != NULL && strlen($val) < $this->min) {
			$this->addError(Yapary_Exception_Error::E_OUT_OF_SIZE);
			return false;
		}
		if ($this->max != NULL && strlen($val) > $this->max) {
			$this->addError(Yapary_Exception_Error::E_OUT_OF_SIZE);
			return false;
		}
		if (!preg_match("/^([ a-z0-9-_\(\)\[\]\{\}\.\#\+\*\\\%\/\&\=\?\:\,\;])*$/i", $val)) {
			$this->addError(Yapary_Exception_Error::E_WRONG_FORMAT);
			return false;
		}

		return true;
	}
}

/**
 * $val muss einem UTF8-String entsprechen
 * mit vorgegebener Unteren- und/oder Oberen Zeichenlaenge
 * */
Class Yapary_Parameter_ParameterCheckStringUtf8 Extends Yapary_Exception_Error Implements IParameterCheck
{
	private $min, $max;
	function __construct ( $_minLength = NULL, $_maxLength = NULL )
	{
		$this->min = $_minLength;
		$this->max = $_maxLength;
	}
	public function typedef ( $val ) { return (string) $val;}
	public function isValid ( $val )
	{
		if (!isset($val)) {
			$this->addError(Yapary_Exception_Error::E_UNDEFINED);
			return false;
		}
		if ($this->min != NULL && strlen($val) < $this->min) {
			$this->addError(Yapary_Exception_Error::E_OUT_OF_SIZE);
			return false;
		}
		if ($this->max != NULL && strlen($val) > $this->max) {
			$this->addError(Yapary_Exception_Error::E_OUT_OF_SIZE);
			return false;
		}
		if (!$this->isValidUtf8($val)) {
			//if( @iconv('UTF-8', 'UTF-8//IGNORE', $var) )
			$this->addError(Yapary_Exception_Error::E_WRONG_FORMAT);
			return false;
		}

		return true;
	}
	private function isValidUtf8 ($str)
	{
		$strlen = strlen($str);
		for ($i=0; $i<$strlen; $i++)
		{
			$ord = ord($str[$i]);
			if($ord < 0x80) {
				continue; // 0bbbbbbb
			} elseif (($ord&0xE0)===0xC0 && $ord>0xC1) {
				$n = 1; // 110bbbbb (exkl C0-C1)
			} elseif (($ord&0xF0)===0xE0) {
				$n = 2; // 1110bbbb
			} elseif (($ord&0xF8)===0xF0 && $ord<0xF5) {
				$n = 3; // 11110bbb (exkl F5-FF)
			} else {
				return false;
			}

			for ($o=0; $o<$n; $o++) { // $n Folgebytes? // 10bbbbbb
				if (++$i === $strlen || (ord($str[$i])&0xC0) !== 0x80) {
					return false;
				}
			}
		}

		return true;
	}
}


/**
 * $val muss einer Email-Adresse entsprechen.
 * Da Umlautdomains und Umlaute in der Email vermieden werden sollten, verbietet die Prufroutine diese
 * mit vorgegebener Oberen Zeichenlaenge
 * */
Class Yapary_Parameter_ParameterCheckEmail Extends Yapary_Exception_Error Implements IParameterCheck
{
	private $max;
	function __construct ( $_maxLength = NULL )
	{
		$this->max = $_maxLength;
	}
	public function typedef ( $val ) { return (string) $val;}
	public function isValid ( $val )
	{
		if (!isset($val)) {
			$this->addError(Yapary_Exception_Error::E_UNDEFINED);
			return false;
		}
		if ($this->max != NULL && strlen($val) > $this->max) {
			$this->addError(Yapary_Exception_Error::E_OUT_OF_SIZE);
			return false;
		}
		if (!preg_match("/^[a-z0-9-]+([\.]?[a-z0-9-])+@[a-z0-9-]+([\.]?[a-z0-9-])+(\.[a-z]{2,4}){1,2}$/i", $val) ) {
			$this->addError(Yapary_Exception_Error::E_WRONG_FORMAT);
			return false;
		}

		return true;
	}
}


/**
 * $val muss einem Zeitstempel im Format 2010-07-13 entsprechen
 * */
Class Yapary_Parameter_ParameterCheckDate Extends Yapary_Exception_Error Implements IParameterCheck
{
	function __construct ( ) { }
	public function typedef ( $val ) { return (string) $val;}
	public function isValid ( $val )
	{
		if (!isset($val)) {
			$this->addError(Yapary_Exception_Error::E_UNDEFINED);
			return false;
		}
		if (!preg_match("/^\d{4}-\d{2}-\d{2}$/", $val)) {
			$this->addError(Yapary_Exception_Error::E_WRONG_FORMAT);
			return false;
		}

		return true;
	}
}


/**
 * $val muss einem Zeitstempel im Format 23:59:59 entsprechen
 * */
Class Yapary_Parameter_ParameterCheckTime Extends Yapary_Exception_Error Implements IParameterCheck
{
	function __construct ( ) { }
	public function typedef ( $val ) { return (string) $val;}
	public function isValid ( $val )
	{
		if (!isset($val)) {
			$this->addError(Yapary_Exception_Error::E_UNDEFINED);
			return false;
		}
		if (!preg_match("/^[0-2][0-3]:[0-5][0-9]:[0-5][0-9]$/", $val)) {
			$this->addError(Yapary_Exception_Error::E_WRONG_FORMAT);
			return false;
		}

		return true;
	}
}


/**
 * $val muss einem Zeitstempel im Format 2010-07-13 23:59:59 entsprechen
 * */
Class Yapary_Parameter_ParameterCheckDateTime Extends Yapary_Exception_Error Implements IParameterCheck
{
	function __construct ( ) { }
	public function typedef ( $val ) { return (string) $val;}
	public function isValid ( $val )
	{
		if (!isset($val)) {
			$this->addError(Yapary_Exception_Error::E_UNDEFINED);
			return false;
		}
		if (!preg_match("/^\d{4}-\d{2}-\d{2} [0-2][0-3]:[0-5][0-9]:[0-5][0-9]$/", $val)) {
			$this->addError(Yapary_Exception_Error::E_WRONG_FORMAT);
			return false;
		}

		return true;
	}
}


/**
 * $val muss einer IPv4-Adresse entsprechen
 * */
Class Yapary_Parameter_ParameterCheckIPv4 Extends Yapary_Exception_Error Implements IParameterCheck
{
	function __construct ( ) { }
	public function typedef ( $val ) { return (string) $val;}
	public function isValid ( $val )
	{
		if (!isset($val)) {
			$this->addError(Yapary_Exception_Error::E_UNDEFINED);
			return false;
		}
		if (!preg_match('/(\d+\.\d+\.\d+\.\d+)/', $val)) {
			$this->addError(Yapary_Exception_Error::E_WRONG_FORMAT);
			return false;
		}
		$arrIPv4 = explode('.', $val);
		while (list(,$val) = each($arrIPv4)) {
		    if ($val<0 || $val>255) { // wenn nicht zwischen {0-255}
		        return false;
		    }
		}

		return true;
	}
}


/**
 * $val muss einem 3- oder 6-stelligen Hex-Wert im Format {#CCC|#C9C9C9} entsprechen
 * */
Class Yapary_Parameter_ParameterCheckHexColor Extends Yapary_Exception_Error Implements IParameterCheck
{
	function __construct ( ) { }
	public function typedef ( $val ) { return (string) $val;}
	public function isValid ( $val )
	{
		if (!isset($val)) {
			$this->addError(Yapary_Exception_Error::E_UNDEFINED);
			return false;
		}
		if (!preg_match("/^(\#)+(([0-9A-F]){3}){1,2}$/i", $val)) {
			$this->addError(Yapary_Exception_Error::E_WRONG_FORMAT);
			return false;
		}

		return true;
	}
}


/**
 * $val muss einem Eintrag des uebergebenen Arrays entsprechen
 * array(0=>'one', 1=>'of', 2=>'them', ...)
 * */
Class Yapary_Parameter_ParameterCheckPartOfArray Extends Yapary_Exception_Error Implements IParameterCheck
{
    private $in_array = NULL;
	function __construct ( array $_in_array )
	{
        $this->in_array = $_in_array;
	}
	public function typedef ( $val ) { return $val;}
	public function isValid ( $val )
	{
		if (!is_array($this->in_array) || count($this->in_array) == 0) {
            throw new Exception('Keine Vergleichsliste vorhanden');
		}
		if (!isset($val)) {
            $this->addError(Yapary_Exception_Error::E_UNDEFINED);
            return false;
		}
        if (!in_array($val, $this->in_array)) {
		    $this->addError(Yapary_Exception_Error::E_OUT_OF_LIST);
	        return false;
        }

        return true;
	}
}



/*
$oParam = new Parameter();
echo $oParam->getParam($var = 10, NULL, $p = new Yapary_Parameter_ParameterCheckNumeric(2,9));
echo $p->getStatus();
*/
?>